`timescale 1ns/1ps
`default_nettype none

/* NOTE:
* - 输出模块状态控制
*/

module pixel_display_general
    #(
    parameter   DW  = 96
    )
    (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // frame
    input  wire         I_frame_sync,
    // control
    input  wire         I_enable,
    // ext setting
    input  wire         I_ext_lock_output,
    input  wire         I_ext_black_screen,
    // config
    input  wire [9:0]   I_cfg_scan_pixel,   // 一扫的像素数量（不包含虚点）
    input  wire [3:0]   I_cfg_gamma_bit,    // gamma bit数, 0 - 1bit, ..., 15 - 16bit
    input  wire [9:0]   I_cfg_scan_length,  // 一扫的像素数量（包含虚点）
    input  wire [4:0]   I_cfg_scan_max,     // 最大扫描id
    input  wire [4:0]   I_cfg_port_max,     // 最大端口id
    input  wire [7:0]   I_cfg_line_pos,     // 换行位置
    input  wire [7:0]   I_cfg_load_width,   // load信号宽度 (>=2)
    input  wire [7:0]   I_cfg_oe_pre_width, // 切换非整周期时oe提前拉低宽度
    input  wire [7:0]   I_cfg_clock_low,     // 时钟低电平时钟数
    input  wire [7:0]   I_cfg_clock_cycle,   // 时钟整周期时钟数
    input  wire [7:0]   I_cfg_clock_phase,   // 时钟相位
    input  wire         I_cfg_data_polarity, // 数据极性
    input  wire [255:0] I_cfg_pwm_setting,   // pwm芯片设置
    // cycle info
    output wire         O_cycle_info_rden,
    output wire [8:0]   O_cycle_info_addr,
    input  wire [15:0]  I_cycle_info_q,
    // frame control
    output wire         O_frame_req,         // 请求帧缓冲
    input  wire [1:0]   I_frame_id,          // 帧缓冲id
    // display control
    input  wire         I_display_reset,       // 强制重新开始串移
    output wire         O_display_ready,       // 输出ready
    output wire         O_display_end,         // 每个显示周期结束标识
    output wire         O_display_chain_end,   // 每个串移周期结束标识
    input  wire         I_display_param_en,    // 更新参数
    input  wire [15:0]  I_display_chain_cycle, // 串移时钟数
    input  wire [15:0]  I_display_extra_cycle, // 额外的串移时钟数
    // read sdram
    output wire         O_read_req,         // 读请求
    input  wire         I_read_busy,        // 读忙碌
    output wire [1:0]   O_read_buf_sel,     // 读取SDRAM分块地址
    output wire [3:0]   O_read_bit_sel,     // 读取的bit选择
    output wire [4:0]   O_read_scan_id,     // 读取的scan id
    output wire [4:0]   O_read_port_max,    // 读取的最大port id
    output wire [9:0]   O_read_pixel_count, // 读取的像素数，总是8的倍数，最多512
    output wire         O_read_buf_index,   // 存放到RAM的id
    // scan output
    output wire         O_scan_prep,
    output wire         O_scan_commit,
    output wire [4:0]   O_scan_num,
    // column addr table
    output wire         O_col_addr_req,
    output wire [8:0]   O_col_addr_index,
    input  wire [8:0]   I_col_addr_data,
    // data buffer
    output wire         O_data_ram_rden,
    output wire [9:0]   O_data_ram_addr,
    input  wire [DW-1:0] I_data_ram_q,
    // led signal
    output wire         O_oe_out,
    output wire         O_load_out,
    output wire         O_clock_out,
    output wire [DW-1:0] O_data_out
);
//------------------------Parameter----------------------
// fsm
localparam [2:0]
    IDLE  = 0,
    PREP0 = 1,
    PREP1 = 2,
    READ  = 3,
    NEXT  = 4,
    LOOP  = 5;

//------------------------Local signal-------------------
// fsm
reg  [2:0]  state;
reg  [2:0]  next;

// cycle info
wire        cycle_rden;
reg  [7:0]  cycle_addr;
reg  [15:0] cycle_q_buf;
reg  [7:0]  row_start_addr;
reg         oe_adj_rden;
wire [3:0]  oe_adj_addr;
reg         adj_q_valid;
reg  [7:0]  adj_q_buf;
reg  [7:0]  oe_adj_val;
reg  [7:0]  oe_adj_buf;

// display control
wire        display_end;
wire        update_param;
reg         display_start;
reg         display_ready;
reg  [15:0] chain_cycle;
reg  [15:0] extra_cycle;
reg  [15:0] chain_cnt;
reg         chain_end;
reg  [4:0]  scan_id;
reg         last_scan;
reg         row_end;
reg         frame_end;

// scan decoder
reg         new_row;
reg         scan_prep;
reg         scan_commit;
reg  [4:0]  row_id;
reg         scan_pending;
reg  [7:0]  line_cnt;

// read sdram
reg  [3:0]  bit_sel;
reg         buf_sel;

// oe control
wire        oe_calc_req;
wire        oe_calc_done;
wire [15:0] oe_calc_max_len;
reg  [3:0]  oe_calc_param0;
reg  [5:0]  oe_calc_param1;
wire [15:0] oe_calc_result;
reg  [15:0] oe_len;
reg         oe_out;
reg         next_frac;
reg         frac;
reg  [15:0] oe_prep_pos;
reg  [15:0] oe_result_buf;
wire [16:0] oe_tmp;
reg  [15:0] oe_final;

// load control
reg         load_out;
reg  [15:0] load_pos;

// chain request
wire        chain_start;    // 串移开始
wire        chain_ram_sel;  // 读取ram起始地址
wire [9:0]  chain_length;   // 串移长度

// data_chain
wire        col_addr_req;
wire [8:0]  col_addr_index;
wire [8:0]  col_addr_data;
wire        data_ram_rden;
wire [9:0]  data_ram_addr;
wire [DW-1:0] data_ram_q;
wire        clock_out;
wire [DW-1:0] data_out;

wire        O_load_out1;
wire        O_oe_out1;
wire        O_clock_out1;
wire [DW-1:0] O_data_out1;

wire        O_load_out2;
wire        O_oe_out2;
wire [DW-1:0] O_data_out2;

wire        O_load_vld;
wire        O_oe_vld;
wire        O_data_vld;

//------------------------Instantiation------------------
// calc_oe_len
calc_oe_len calc (/*{{{*/
    .I_sclk         ( I_sclk ),
    .I_rst_n        ( I_rst_n ),
    .I_calc_req     ( oe_calc_req ),
    .O_calc_done    ( oe_calc_done ),
    .I_calc_max_len ( oe_calc_max_len ),
    .I_calc_param0  ( oe_calc_param0 ),
    .I_calc_param1  ( oe_calc_param1 ),
    .O_calc_result  ( oe_calc_result )
);/*}}}*/

// data_chain
data_chain /*{{{*/
    #(
    .DW                  (DW      )
    )
  chain (
    .I_sclk              ( I_sclk ),
    .I_rst_n             ( I_rst_n ),
    .I_cfg_clock_low     ( I_cfg_clock_low ),
    .I_cfg_clock_cycle   ( I_cfg_clock_cycle ),
    .I_cfg_clock_phase   ( I_cfg_clock_phase ),
    .I_cfg_data_polarity ( I_cfg_data_polarity ),
    .I_chain_start       ( chain_start ),
    .I_chain_ram_sel     ( chain_ram_sel ),
    .I_chain_length      ( chain_length ),
    .O_col_addr_req      ( col_addr_req ),
    .O_col_addr_index    ( col_addr_index ),
    .I_col_addr_data     ( I_col_addr_data ),
    .O_data_ram_rden     ( data_ram_rden ),
    .O_data_ram_addr     ( data_ram_addr ),
    .I_data_ram_q        ( I_data_ram_q ),
    .O_chain_clock       ( clock_out ),
    .O_chain_data        ( data_out )
);/*}}}*/

// cxy_general_wr_reg
cxy_general_wr_reg /*{{{*/
    #(
    .DW                 (DW                 )
    )
  gwr (
    .I_sclk             (I_sclk             ),
    .I_rst_n            (I_rst_n            ),

    .I_enable           (I_enable           ),
    .I_cfg_gamma_bit    (I_cfg_gamma_bit    ),
    .I_cfg_scan_length  (I_cfg_scan_length  ),
    .I_cfg_pwm_setting  (I_cfg_pwm_setting  ),

    .I_read_req         (O_read_req         ),
    .I_read_busy        (I_read_busy        ),
    .I_read_bit_sel     (O_read_bit_sel     ),

    .I_frame_sync       (I_frame_sync       ),

    .I_clock_in         (O_clock_out1       ),
    .I_load_in          (O_load_out1        ),
    .I_oe_in            (O_oe_out1          ),

    .O_load_vld         (O_load_vld         ),
    .O_load_out         (O_load_out2        ),
                                            
    .O_oe_vld           (O_oe_vld           ),
    .O_oe_out           (O_oe_out2          ),
                                            
    .O_data_vld         (O_data_vld         ),
    .O_data_out         (O_data_out2        )
    );/*}}}*/

assign O_oe_out    = O_oe_vld   ? O_oe_out2   : O_oe_out1;
assign O_load_out  = O_load_vld ? O_load_out2 : O_load_out1;
assign O_data_out  = O_data_vld ? O_data_out2 : O_data_out1;
assign O_clock_out = O_clock_out1;

//------------------------Body---------------------------
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
// state
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= IDLE;
    else if (I_display_reset) // 强制同步
        state <= IDLE;
    else
        state <= next;
end

// next
always @(*) begin
    case (state)
        IDLE: begin
            next = PREP0;
        end

        PREP0: begin
            next = PREP1;
        end

        PREP1: begin
            next = READ;
        end

        READ: begin
            next = NEXT;
        end

        NEXT: begin
            next = LOOP;
        end

        LOOP: begin
            if (~chain_end)
                next = LOOP;
            else
                next = READ;
        end
        
        default: begin
            next = IDLE;
        end
    endcase
end

//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++cycle info+++++++++++++++++++++
assign O_cycle_info_rden = (!I_enable)? 1'b0 : (cycle_rden | oe_adj_rden);
assign O_cycle_info_addr = (!I_enable)? 1'b0
                         : oe_adj_rden? {1'b1, 4'd0, oe_adj_addr}
                         : cycle_addr;

assign cycle_rden = (state == PREP0 || state == NEXT);

// cycle_addr
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cycle_addr <= 1'b0;
    else if (state == IDLE)
        cycle_addr <= 1'b0;
    else if (state == READ) begin
        if (~cycle_q_buf[8])
            cycle_addr <= cycle_addr + 1'b1;
        else if (~last_scan)
            cycle_addr <= row_start_addr;
        else if (cycle_q_buf[9])
            cycle_addr <= 1'b0;
        else
            cycle_addr <= cycle_addr + 1'b1;
    end
end

// cycle_q_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        cycle_q_buf <= 1'b0;
    else if (oe_adj_rden)
        cycle_q_buf <= I_cycle_info_q;
end

// oe_adj_rden
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        oe_adj_rden <= 1'b0;
    else
        oe_adj_rden <= cycle_rden;
end

assign oe_adj_addr = I_cycle_info_q[3:0];

// adj_q_valid
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        adj_q_valid <= 1'b0;
    else
        adj_q_valid <= oe_adj_rden;
end

// adj_q_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        adj_q_buf <= 1'b0;
    else if (adj_q_valid) begin
      //if (I_cycle_info_q[15:8] == 8'hff)
        if (I_cycle_info_q[15] == 1)
            adj_q_buf <= 1'b0;
        else
            adj_q_buf <= I_cycle_info_q[7:0];
    end
end

// oe_adj_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        oe_adj_buf <= 1'b0;
    else if (state == NEXT)
        oe_adj_buf <= adj_q_buf;
end

// oe_adj_val
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        oe_adj_val <= 1'b0;
    else if (oe_calc_req)
        oe_adj_val <= oe_adj_buf;
end

// row_start_addr
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        row_start_addr <= 1'b0;
    else if (state == PREP1)
        row_start_addr <= 1'b0;
    else if (state == NEXT && row_end && last_scan)
        row_start_addr <= cycle_addr;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++frame control++++++++++++++++++
assign O_frame_req = I_enable && !I_ext_lock_output && display_start;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++display control++++++++++++++++
assign O_display_end = (!I_enable)? 1'b0 : display_end;
assign O_display_chain_end = (!I_enable)? 1'b0 : chain_end;

assign O_display_ready = display_ready;
assign display_end  = (state == LOOP) && chain_end && last_scan && frame_end;
assign update_param = (state == PREP1) || (display_end && I_display_param_en);

// display_ready
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        display_ready <= 1'b0;
    else if (!I_enable)
        display_ready <= 1'b0;
    else
        display_ready <= 1'b1;
end

// display_start
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        display_start <= 1'b0;
    else if (state == PREP1)
        display_start <= 1'b1;
    else if (display_end)
        display_start <= 1'b1;
    else
        display_start <= 1'b0;
end

// chain_cycle
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        chain_cycle <= 1'b0;
    else if (update_param)
        chain_cycle <= I_display_chain_cycle;
end

// extra_cycle
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        extra_cycle <= 1'b0;
    else if (update_param)
        extra_cycle <= I_display_extra_cycle;
    else if (chain_end && extra_cycle > 1'b0)
        extra_cycle <= extra_cycle - 1'b1;
end

// chain_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        chain_cnt <= 1'b1;
    else if (state == IDLE || state == PREP0 || state == PREP1)
        chain_cnt <= 1'b1;
    else if (chain_end) begin
        if (extra_cycle > 1'b0)
            chain_cnt <= 1'b0;
        else
            chain_cnt <= 1'b1;
    end
    else
        chain_cnt <= chain_cnt + 1'b1;
end

// chain_end
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        chain_end <= 1'b0;
    else
        chain_end <= (chain_cnt == chain_cycle - 1'b1);
end

// scan_id
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        scan_id <= 1'b0;
    else if (state == PREP1)
        scan_id <= 1'b0;
    else if (chain_end && row_end) begin
        if (last_scan)
            scan_id <= 1'b0;
        else
            scan_id <= scan_id + 1'b1;
    end
end

// last_scan
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        last_scan <= 1'b0;
    else
        last_scan <= (scan_id == I_cfg_scan_max);
end

// row_end
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        row_end <= 1'b0;
    else if (state == READ)
        row_end <= cycle_q_buf[8];
end

// frame_end
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        frame_end <= 1'b0;
    else if (state == READ)
        frame_end <= cycle_q_buf[9];
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++read sdram+++++++++++++++++++++
assign O_read_req         = (!I_enable)? 1'b0 : (state == NEXT);
assign O_read_buf_sel     = (!I_enable)? 1'b0 : I_frame_id;
assign O_read_bit_sel     = (!I_enable)? 1'b0 : bit_sel;
assign O_read_scan_id     = (!I_enable)? 1'b0 : scan_id;
assign O_read_port_max    = (!I_enable)? 1'b0 : I_cfg_port_max;
assign O_read_pixel_count = (!I_enable)? 1'b0 : I_cfg_scan_pixel;
assign O_read_buf_index   = (!I_enable)? 1'b0 : buf_sel;

// bit_sel
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        bit_sel <= 1'b0;
    else if (state == READ)
        bit_sel <= cycle_q_buf[3:0];
end

// buf_sel
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        buf_sel <= 1'b0;
    else if (chain_end)
        buf_sel <= ~buf_sel;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++data chain+++++++++++++++++++++
assign chain_start   = chain_end;
assign chain_ram_sel = buf_sel;
assign chain_length  = I_cfg_scan_length;

assign O_col_addr_req   = (!I_enable)? 1'b0 : col_addr_req;
assign O_col_addr_index = (!I_enable)? 1'b0 : col_addr_index;
assign O_data_ram_rden  = (!I_enable)? 1'b0 : data_ram_rden;
assign O_data_ram_addr  = (!I_enable)? 1'b0 : data_ram_addr;
assign O_clock_out1     = (!I_enable)? 1'b0 : clock_out;
assign O_data_out1      = (!I_enable)? 1'b0 : data_out;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++oe control+++++++++++++++++++++
assign O_oe_out1 = (!I_enable) ? 1'b0 : oe_out;

assign oe_calc_req     = chain_end;
assign oe_calc_max_len = chain_cycle;

// oe_calc_param0
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        oe_calc_param0 <= 1'b0;
    else if (state == READ)
        oe_calc_param0 <= cycle_q_buf[7:4];
end

// oe_calc_param1
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        oe_calc_param1 <= 1'b0;
    else if (state == READ)
        oe_calc_param1 <= cycle_q_buf[15:10];
end

// oe_result_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        oe_result_buf <= 1'b0;
    else if (oe_calc_done)
        oe_result_buf <= oe_calc_result;
end

assign oe_tmp = oe_result_buf + {{10{oe_adj_val[7]}}, oe_adj_val[6:0]};

// oe_final
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        oe_final <= 1'b0;
    else if (oe_result_buf == 1'b0)
        oe_final <= 1'b0;
    else if (oe_tmp[16] == 1'b0 && oe_tmp[15:0] != 1'b0) // 未溢出
        oe_final <= oe_tmp[15:0];
    else if (oe_adj_val[7]) // 向下溢出
        oe_final <= 1'b1;
    else // 向上溢出
        oe_final <= 16'hffff;
end

// oe_len
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        oe_len <= 1'b0;
    else if (state == PREP1)
        oe_len <= 1'b0;
    else if (chain_end)
        oe_len <= oe_final;
end

// oe_out
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        oe_out <= 1'b1;
    else if (I_ext_black_screen)
        oe_out <= 1'b0;
    else if (state == IDLE || state == PREP1)
        oe_out <= 1'b0;
    else if (chain_end) begin
        if (oe_final > 1'b0)
            oe_out <= 1'b1;
        else
            oe_out <= 1'b0;
    end
    // NOTE: 总是串移链最后关闭oe，兼容双锁存芯片时序
    //else if (!frac && next_frac && chain_cnt == oe_prep_pos)
    else if (chain_cnt == oe_prep_pos)
        oe_out <= 1'b0;
    else if (chain_cnt == oe_len)
        oe_out <= 1'b0;
end

// next_frac
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        next_frac <= 1'b0;
    else if (chain_end)
        next_frac <= (oe_calc_param0 != 1'b0);
end

// frac
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        frac <= 1'b0;
    else if (chain_end)
        frac <= next_frac;
end

// oe_prep_pos
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        oe_prep_pos <= 1'b1;
    else if (update_param)
        oe_prep_pos <= I_display_chain_cycle - I_cfg_oe_pre_width;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++scan decode++++++++++++++++++++
assign O_scan_prep   = (!I_enable)? 1'b0 : scan_prep;
assign O_scan_num    = (!I_enable)? 1'b0 : row_id;
assign O_scan_commit = (!I_enable)? 1'b0 : scan_commit;

// new_row
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        new_row <= 1'b0;
    else if (chain_end)
        new_row <= row_end;
end

// scan_prep
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_prep <= 1'b0;
    else if (chain_end && new_row)
        scan_prep <= 1'b1;
    else
        scan_prep <= 1'b0;
end

// row_id
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        row_id <= 1'b0;
    else if (chain_end && new_row)
        row_id <= scan_id;
end

// scan_commit
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_commit <= 1'b0;
    else if (scan_pending && oe_out == 1'b0 && line_cnt == I_cfg_line_pos - 1'b1)
        scan_commit <= 1'b1;
    else
        scan_commit <= 1'b0;
end

// scan_pending
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_pending <= 1'b0;
    else if (scan_prep)
        scan_pending <= 1'b1;
    else if (scan_commit)
        scan_pending <= 1'b0;
end

// line_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        line_cnt <= 1'b1;
    else if (state == IDLE || state == PREP1)
        line_cnt <= 1'b1;
    else if (oe_out == 1'b1)
        line_cnt <= 1'b1;
    else if (line_cnt < 8'd255)
        line_cnt <= line_cnt + 1'b1;
end

//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++load control+++++++++++++++++++
assign O_load_out1 = (!I_enable) ? 1'b0 : load_out;

// load_out
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        load_out <= 1'b0;
    else if (state == IDLE || state == PREP1)
        load_out <= 1'b0;
    else if (chain_cnt == chain_cycle - 1'b1)
        load_out <= 1'b0;
    else if (chain_cnt == load_pos)
        load_out <= 1'b1;
end

// load_pos
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        load_pos <= 1'b1;
    else if (update_param)
        load_pos <= I_display_chain_cycle - I_cfg_load_width - 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
